﻿/*
 * The copyright statement below is for NLog.
 * See http://nlog-project.org for more information.

Copyright (c) 2004-2011 Jaroslaw Kowalski <jaak@jkowalski.net>

All rights reserved.

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions 
are met:

* Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer. 

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution. 

* Neither the name of Jaroslaw Kowalski nor the names of its 
  contributors may be used to endorse or promote products derived from this
  software without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using NLog;

namespace PluginLogger
{
	/// <summary>
	/// Provides values for log event types
	/// </summary>
	public enum LogEventType
	{
		/// <summary>
		/// General information
		/// </summary>
		Information,
		/// <summary>
		/// Successful login
		/// </summary>
		Login,
		/// <summary>
		/// Failed login
		/// </summary>
		LoginFailed,
		/// <summary>
		/// Successful object update
		/// </summary>
		ObjectUpdate,
		/// <summary>
		/// Failed object update
		/// </summary>
		ObjectUpdateFailed,
		/// <summary>
		/// Operation cancelled
		/// </summary>
		OperationCancelled,
		/// <summary>
		/// Operation failed
		/// </summary>
		OperationFailed,
		/// <summary>
		/// Operatin succeeded
		/// </summary>
		OperationSuccess,
		/// <summary>
		/// Read resource succeeded
		/// </summary>
		ReadResource,
		/// <summary>
		/// Read resource failed
		/// </summary>
		ReadResourceFailed,
		/// <summary>
		/// Read setting succeeded
		/// </summary>
		ReadSetting,
		/// <summary>
		/// Read setting failed
		/// </summary>
		ReadSettingFailed
	}

	/// <summary>
	/// Provides logging methods and information.
	/// </summary>
	public class LoggerWrapper
	{
		#region Fields (1) 

		/// <summary>
		/// Instance of <see cref="NLog.Logger"/> to use for creating log files and writing log entries.
		/// </summary>
		/// <seealso href="http://nlog-project.org/doc/2.0/netfx40/html/T_NLog_Logger.htm"/>
		private Logger logger;

		#endregion Fields 

		#region Constructors (1) 

		/// <summary>
		/// Creates a new instance of the <see cref="LoggerWrapper"/> class.
		/// </summary>
		/// <param name="name">Name of the logger</param>
		/// <param name="nlogConfigFileName">File name of the NLog configuration file</param>
		/// <param name="logFileName">Formatted file name of the log file</param>
		/// <remarks>If nlogConfigFileName is null or empty, "NLog.config" is used. If logFileName is null or empty, "logfile_${shortdate}.log" is used.</remarks>
		/// <seealso href="http://nlog-project.org/help/NLog.Config.html"/>
		/// <seealso href="http://nlog-project.org/help/NLog.Config.XmlLoggingConfiguration.html"/>
		/// <seealso href="http://nlog-project.org/help/NLog.Layout.html"/>
		/// <seealso href="http://nlog-project.org/help/NLog.Targets.html"/>
		/// <seealso href="http://nlog-project.org/help/NLog.LogManager.html"/>
		public LoggerWrapper(string name, string nlogConfigFileName, string logFileName)
		{
			if (String.IsNullOrEmpty(nlogConfigFileName))
			{
				nlogConfigFileName = "NLog.config";
			}
			if (String.IsNullOrEmpty(logFileName))
			{
				logFileName = "logfile_${shortdate}.log";
			}
			string configFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), nlogConfigFileName);
			NLog.Config.XmlLoggingConfiguration xmlConfig = new NLog.Config.XmlLoggingConfiguration(configFile);
			NLog.Layouts.SimpleLayout fileName = (NLog.Layouts.SimpleLayout)((NLog.Targets.FileTarget)xmlConfig.ConfiguredNamedTargets[0]).FileName;
			NLog.Layouts.SimpleLayout logFile = new NLog.Layouts.SimpleLayout();
			string logFilePath = Path.GetDirectoryName(configFile);
			logFile.Text = Path.Combine(logFilePath, logFileName);
			((NLog.Targets.FileTarget)xmlConfig.ConfiguredNamedTargets[0]).FileName = logFile;
			LogManager.Configuration = xmlConfig;
			logger = LogManager.GetLogger(name);
		}

		#endregion Constructors 

		#region Methods (13) 

		// Public Methods (13) 

		/// <summary>
		/// Writes a log entry for a fatal exception.
		/// </summary>
		/// <param name="eventType">Type of log event</param>
		/// <param name="ex">Exception that generated the event</param>
		public void WriteFatalException(LogEventType eventType, Exception ex)
		{
			WriteLog(LogLevel.Fatal, eventType, ex.Message);
		}

		/// <summary>
		/// Writes an information log entry
		/// </summary>
		/// <param name="eventType">Type of log event</param>
		public void WriteInfo(LogEventType eventType)
		{
			WriteInfo(eventType, String.Empty);
		}

		/// <summary>
		/// Writes an information log entry
		/// </summary>
		/// <param name="eventType">Type of log event</param>
		/// <param name="message">Message for the log entry</param>
		public void WriteInfo(LogEventType eventType, string message)
		{
			WriteLog(LogLevel.Info, eventType, message);
		}

		/// <summary>
		/// Writes an information log entry
		/// </summary>
		/// <param name="eventType">Type of log event</param>
		/// <param name="aitUser">Author-it user</param>
		/// <param name="objectId">Author-it object ID</param>
		/// <param name="objectDescription">Author-it object description</param>
		public void WriteInfo(LogEventType eventType, string aitUser, int? objectId, string objectDescription)
		{
			WriteLog(LogLevel.Info, eventType, aitUser, objectId, objectDescription);
		}

		/// <summary>
		/// Writes an information log entry
		/// </summary>
		/// <param name="eventType">Type of log event</param>
		/// <param name="aitUser">Author-it user</param>
		/// <param name="objectId">Author-it object ID</param>
		/// <param name="objectDescription">Author-it object description</param>
		/// <param name="message">Message for the log entry</param>
		public void WriteInfo(LogEventType eventType, string aitUser, int? objectId, string objectDescription, string message)
		{
			WriteLog(LogLevel.Info, eventType, aitUser, objectId, objectDescription, message);
		}

		/// <summary>
		/// Writes a log entry
		/// </summary>
		/// <param name="level">Logging level</param>
		/// <param name="eventType">Type of log event</param>
		public void WriteLog(LogLevel level, LogEventType eventType)
		{
			WriteLog(level, eventType, String.Empty);
		}

		/// <summary>
		/// Writes a log entry
		/// </summary>
		/// <param name="level">Logging level</param>
		/// <param name="eventType">Type of log event</param>
		/// <param name="message">Message for the log entry</param>
		public void WriteLog(LogLevel level, LogEventType eventType, string message)
		{
			WriteLog(level, eventType, String.Empty, null, String.Empty, message);
		}

		/// <summary>
		/// Writes a log entry
		/// </summary>
		/// <param name="level">Logging level</param>
		/// <param name="eventType">Type of log event</param>
		/// <param name="aitUser">Author-it user</param>
		/// <param name="objectId">Author-it object ID</param>
		/// <param name="objectDescription">Author-it object description</param>
		public void WriteLog(LogLevel level, LogEventType eventType, string aitUser, int? objectId, string objectDescription)
		{
			WriteLog(level, eventType, aitUser, objectId, objectDescription, String.Empty);
		}

		/// <summary>
		/// Writes a log entry
		/// </summary>
		/// <param name="level">Logging level</param>
		/// <param name="eventType">Type of log event</param>
		/// <param name="aitUser">Author-it user</param>
		/// <param name="objectId">Author-it object ID</param>
		/// <param name="objectDescription">Author-it object description</param>
		/// <param name="message">Message for the log entry</param>
		public void WriteLog(LogLevel level, LogEventType eventType, string aitUser, int? objectId, string objectDescription, string message)
		{
			LogEventInfo eventInfo = new LogEventInfo();
			eventInfo.Level = level;
			eventInfo.TimeStamp = DateTime.Now;
			eventInfo.LoggerName = logger.Name;
			eventInfo.Message = message;
			eventInfo.Properties.Add("EventType", eventType);
			eventInfo.Properties.Add("AuthoritUser", aitUser);
			eventInfo.Properties.Add("ObjectId", objectId);
			eventInfo.Properties.Add("ObjectDescription", objectDescription);
			logger.Log(typeof(LoggerWrapper), eventInfo);
		}

		/// <summary>
		/// Writes a log entry for a failed login
		/// </summary>
		/// <param name="aitUser">Author-it user</param>
		/// <param name="databaseName">Database that contains the Author-it library</param>
		/// <param name="result">Login result</param>
		public void WriteLoginFailed(string aitUser, string databaseName, string result)
		{
			string message = String.Concat(databaseName, ":", result);
			WriteLog(LogLevel.Error, LogEventType.LoginFailed, message);
		}

		/// <summary>
		/// Writes a log entry for a successful login
		/// </summary>
		/// <param name="aitUser">Author-it user</param>
		/// <param name="database">Database that contains the Author-it library</param>
		public void WriteLoginSuccess(string aitUser, string database)
		{
			WriteLog(LogLevel.Info, LogEventType.Login, aitUser, null, null, database);
		}

		/// <summary>
		/// Writes a log entry for a successful resource read
		/// </summary>
		/// <param name="resourceName">Name of the resource</param>
		/// <param name="resourceValue">Value of the resource</param>
		public void WriteResourceRead(string resourceName, string resourceValue)
		{
			string message = String.Format("'{0}' = '{1}'", resourceName, resourceValue);
			WriteInfo(LogEventType.ReadResource, message);
		}

		/// <summary>
		/// Writes a log entry for a successful setting read
		/// </summary>
		/// <param name="settingName">Name of the setting</param>
		/// <param name="settingValue">Value of the setting</param>
		public void WriteSettingRead(string settingName, string settingValue)
		{
			string logMessage = String.Format("'{0}' = '{1}'", settingName, settingValue);
			WriteInfo(LogEventType.ReadSetting, logMessage);
		}

		#endregion Methods 
	}
}
